/*
 * Copyright (C) 2014 Realtek Semiconductor Corp.
 * All Rights Reserved.
 *
 * This program is the proprietary software of Realtek Semiconductor
 * Corporation and/or its licensors, and only be used, duplicated,
 * modified or distributed under the authorized license from Realtek.
 *
 * ANY USE OF THE SOFTWARE OTHER THAN AS AUTHORIZED UNDER
 * THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
 *
 * Purpose : Definition of ME handler: FTTR MQTT Agent (65509)
 *
 * Feature : The file includes the following modules and sub-modules
 *           (1) ME handler: FTTR MQTT Agent (65509)
 */

#include "app_basic.h"
#ifndef OMCI_X86
#include "common/error.h"
#endif
#include "feature_mgmt.h"

MIB_TABLE_INFO_T gMibFttrMqttAgentTableInfo;
MIB_ATTR_INFO_T  gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_ATTR_NUM];
MIB_TABLE_FTTRMQTTAGENT_T gMibFttrMqttAgentDefRow;
MIB_TABLE_OPER_T gMibFttrMqttAgentOper;

extern omci_mulget_info_ts gOmciMulGetData[OMCI_MSG_BASELINE_PRI_NUM];


static void ControllerEntry_to_network(omci_controller_tbl_entry_t *pRawEntry, omci_controller_tbl_entry_t *pOutData)
{
	pOutData->controller_network_addr           = GOS_Htons(pRawEntry->controller_network_addr);
	pOutData->tableCtrl							= pRawEntry->tableCtrl;
	pOutData->associatedTag           			= GOS_Htons(pRawEntry->associatedTag);
	pOutData->provisioning_code              	= GOS_Htons(pRawEntry->provisioning_code);
	pOutData->usp_retry_min_wait_interval    	= GOS_Htons(pRawEntry->usp_retry_min_wait_interval);
	pOutData->usp_retry_interval_multiplier     = GOS_Htons(pRawEntry->usp_retry_interval_multiplier);
	memcpy(pOutData->mtp_used, pRawEntry->mtp_used, MIB_TABLE_AVLUSPMTPTABLE_LEN);
	GOS_HtonByte(pOutData->mtp_used, MIB_TABLE_AVLUSPMTPTABLE_LEN);

}

static GOS_ERROR_CODE omci_mib_fttr_mqtt_agent_reset(UINT32 args_num, ...)
{
    MIB_TABLE_FTTRMQTTAGENT_T	mibFttrMqttAgent;
	MIB_TABLE_VEIP_T			veip;
	UINT32						slotNum, ret, curTblEntryCnt = 0, times, idx;
	mgmt_cfg_msg_t				mgmtInfo;
	
	omci_dm_avl_usp_mtp_entry_t uspMtpEntry[USP_SERVER_NAME_ENTRY_CNT_PER_GET];

	slotNum = TXC_GET_SLOT_NUM_BY_SLOT_ID(TXC_CARDHLD_VEIP_SLOT);

    feature_api(FEATURE_API_ME_00000100, &slotNum);

    veip.EntityId   = (UINT16)((slotNum << 8) | 1);

    if (GOS_OK == MIB_Get(MIB_TABLE_VEIP_INDEX, &veip, sizeof(MIB_TABLE_VEIP_T)))
    {
		OMCI_LOG(OMCI_LOG_LEVEL_INFO, "Resetting MIB: Extended FTTR MQTT Agent");
		MIB_Default(MIB_TABLE_FTTRMQTTAGENT_INDEX, &mibFttrMqttAgent, sizeof(MIB_TABLE_FTTRMQTTAGENT_T));
		mibFttrMqttAgent.EntityId = veip.EntityId;
		mibFttrMqttAgent.curAvlUspMtpEntryCnt = 0;
		LIST_INIT(&(mibFttrMqttAgent.avlUspMtphead));

		mibFttrMqttAgent.curControllerEntryCnt = 0;
		LIST_INIT(&(mibFttrMqttAgent.controllerhead));
						

		// get onu available usp message transfer protocol.
		memset(&mgmtInfo, 0, sizeof(mgmt_cfg_msg_t));
		mgmtInfo.op_id = OP_GET_USP_SERVICE_NAME_CNT;
		ret = feature_api(FEATURE_API_L3SVC_MGMT_CFG_SET, &mgmtInfo, sizeof(mgmt_cfg_msg_t));
		if (FAL_OK == ret)
		{
			times = 0;
			curTblEntryCnt = mgmtInfo.cfg.usp.uspTblCnt;
			while (curTblEntryCnt > 0)
			{
				memset(&mgmtInfo, 0, sizeof(mgmt_cfg_msg_t));
				mgmtInfo.op_id = OP_GET_USP_SERVICE_NAME;
				mgmtInfo.cfg.usp.position = times * USP_SERVER_NAME_ENTRY_CNT_PER_GET;
				if (curTblEntryCnt >= USP_SERVER_NAME_ENTRY_CNT_PER_GET)
				{
					mgmtInfo.cfg.usp.entryCnt = USP_SERVER_NAME_ENTRY_CNT_PER_GET;
				}
				else
				{
					mgmtInfo.cfg.usp.entryCnt = curTblEntryCnt; //for get number 
				}
				mgmtInfo.cfg.usp.tbl_entry.pAvl_service_name = (omci_dm_avl_usp_mtp_entry_t *)&uspMtpEntry[0];
				memset(&uspMtpEntry[0], 0x0, sizeof(omci_dm_avl_usp_mtp_entry_t)*mgmtInfo.cfg.usp.entryCnt);
				ret = feature_api(FEATURE_API_L3SVC_MGMT_CFG_SET, &mgmtInfo, sizeof(mgmt_cfg_msg_t));
				if(FAL_OK != ret)
				{
					OMCI_LOG(OMCI_LOG_LEVEL_ERR, " %s()@%d ERR ret=%u", __FUNCTION__, __LINE__, ret);
				}
				for (idx = 0; idx < mgmtInfo.cfg.usp.entryCnt; idx++)
				{
					avlUspMtpTableEntry_t *pNew = (avlUspMtpTableEntry_t *)malloc(sizeof(avlUspMtpTableEntry_t));
					if (pNew)
					{
						memcpy(pNew->serviceName, mgmtInfo.cfg.usp.tbl_entry.pAvl_service_name->service_name, MIB_TABLE_AVLUSPMTPTABLE_LEN);
						LIST_INSERT_HEAD(&(mibFttrMqttAgent.avlUspMtphead), pNew, entries);
						mibFttrMqttAgent.curAvlUspMtpEntryCnt++;
					}
					mgmtInfo.cfg.usp.tbl_entry.pAvl_service_name++;
				}
				times++;
				curTblEntryCnt -= mgmtInfo.cfg.usp.entryCnt;
			}
			
		}
		#if 0
		else
		{
			// self-debugging
			unsigned char	protocols[6][16] = 
			{
				"usp-agt-mqtt",
				"usp-agt-coAP",
				"usp-agt-stomp",
				"usp-agt-ws",
				"usp-agt-n1",
				"usp-agt-n2"
			};
			for (idx = 0; idx < 6; idx++)
			{
				avlUspMtpTableEntry_t *pNew = (avlUspMtpTableEntry_t *)malloc(sizeof(avlUspMtpTableEntry_t));
				if (pNew)
				{
					memcpy(pNew->serviceName, protocols[idx], MIB_TABLE_AVLUSPMTPTABLE_LEN);
					LIST_INSERT_HEAD(&(mibFttrMqttAgent.avlUspMtphead), pNew, entries);
					mibFttrMqttAgent.curAvlUspMtpEntryCnt++;
				}
			}	
		}
		#endif
		GOS_ASSERT(GOS_OK == MIB_Set(MIB_TABLE_FTTRMQTTAGENT_INDEX, &mibFttrMqttAgent, sizeof(MIB_TABLE_FTTRMQTTAGENT_T)));
		OMCI_MeOperCfg(MIB_TABLE_FTTRMQTTAGENT_INDEX, NULL, &mibFttrMqttAgent, MIB_ADD,
			omci_GetOltAccAttrSet(MIB_TABLE_FTTRMQTTAGENT_INDEX, OMCI_ME_ATTR_ACCESS_SBC), OMCI_MSG_BASELINE_PRI_LOW);
		
    }
	
    return GOS_OK;

}

GOS_ERROR_CODE FttrMqttAgentDumpMib(void *pData, MIB_TABLE_INFO_T *pTblInfo)
{
	avlUspMtpTableEntry_t *pEntry = NULL;
	controllerTableEntry_t *pControllerEntry = NULL;
	omci_controller_tbl_entry_t	*pRowEntry = NULL;
	UINT16 count = 0;
	MIB_TABLE_FTTRMQTTAGENT_T *pFttrMqttAgent = (MIB_TABLE_FTTRMQTTAGENT_T*)pData;
	
	OMCI_PRINT("EntityId: 0x%02x", pFttrMqttAgent->EntityId);
	OMCI_PRINT("%s:", pTblInfo->pAttributes[MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX-1].Desc);
	OMCI_PRINT("========================================");
	LIST_FOREACH(pEntry, &pFttrMqttAgent->avlUspMtphead, entries)
	{
		OMCI_PRINT("---------------------------------------");
		OMCI_PRINT("INDEX: %u", count);
		OMCI_PRINT("%s: %s", "Service name", pEntry->serviceName);
		count++;
	}
	if(0 == count)
		OMCI_PRINT("No entry");
	OMCI_PRINT("========================================\n");

	count = 0;
	OMCI_PRINT("%s:", pTblInfo->pAttributes[MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX-1].Desc);
	OMCI_PRINT("========================================");
	LIST_FOREACH(pControllerEntry, &pFttrMqttAgent->controllerhead, entries)
	{
		pRowEntry = &pControllerEntry->tableEntry;
		OMCI_PRINT("---------------------------------------");
		OMCI_PRINT("INDEX: %u", count);
		OMCI_PRINT("%s: 0x%04x", "Controller network address", pRowEntry->controller_network_addr);
		OMCI_PRINT("%s: 0x%04x", "Associated tag", pRowEntry->associatedTag);
		OMCI_PRINT("%s: 0x%04x", "Provisioning Code", pRowEntry->provisioning_code);
		OMCI_PRINT("%s: %hu", "USP retry minimum wait interval", pRowEntry->usp_retry_min_wait_interval);
		OMCI_PRINT("%s: %hu", "USP retry interval multiplier", pRowEntry->usp_retry_interval_multiplier);
		OMCI_PRINT("%s: %s", "Message Transfer Protocol (MTP) Used", pRowEntry->mtp_used);
		//OMCI_PRINT("%s: 0x%04x", "Forward Address", pRowEntry->forward_addr);
		//OMCI_PRINT("%s: %hu", "Retry After Forward Fail Seconds", pRowEntry->retry_second);
		//OMCI_PRINT("%s: 0x%04x", "Backup Server IP address", pRowEntry->backup_server);
		count++;
	}
	if(0 == count)
		OMCI_PRINT("No entry");
	OMCI_PRINT("========================================");

	return GOS_OK;
}

GOS_ERROR_CODE
FttrMqttAgentAttrTypeTableMibGet (
    MIB_TABLE_FTTRMQTTAGENT_T* pMe,
    MIB_ATTRS_SET attrSet,
    UINT32        pri)
{
    MIB_ATTR_INDEX attrIndex;
    controllerTableEntry_t* pEntry = NULL;
	avlUspMtpTableEntry_t * pMtpEntry = NULL;
    omci_controller_tbl_entry_t ctrlRawEntry;
	UINT8   					serviceName[MIB_TABLE_AVLUSPMTPTABLE_LEN];
    UINT8* ptr = NULL;
    UINT32 attrSize;

    if (!pMe) {
        OMCI_LOG(OMCI_LOG_LEVEL_DBG, "%s: pMe Pointer is NULL\n", __FUNCTION__);
        return GOS_FAIL;
    }

    if (MIB_IsInAttrSet(&attrSet, MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX)) {

        attrSize = MIB_TABLE_CONTROLLERTABLE_LEN * (pMe->curControllerEntryCnt);
        attrIndex = MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX;
    
        ptr  = gOmciMulGetData[pri].attribute[attrIndex].pAttrValue; 
        if(ptr && attrSize != gOmciMulGetData[pri].attribute[attrIndex].attrSize)/*attrSize change , first free old buffer */
        {
            OMCI_LOG(OMCI_LOG_LEVEL_WARN, "%s() %d ptr=0x%p, size= %u", __FUNCTION__, __LINE__, ptr, gOmciMulGetData[pri].attribute[attrIndex].attrSize);
            gOmciMulGetData[pri].attribute[attrIndex].pAttrValue = NULL;
			free(ptr);
            ptr = NULL;
        }
        
        if(NULL == ptr && attrSize>0) /*Allocate new buffer */
        {
            gOmciMulGetData[pri].attribute[attrIndex].pAttrValue = (UINT8 *)malloc(attrSize);
            ptr  = gOmciMulGetData[pri].attribute[attrIndex].pAttrValue; 
            OMCI_LOG(OMCI_LOG_LEVEL_WARN, "%s() %d ptr=0x%p, size= %u", __FUNCTION__, __LINE__, ptr, attrSize);    
        }


        gOmciMulGetData[pri].attribute[attrIndex].attrSize = attrSize;
        gOmciMulGetData[pri].attribute[attrIndex].attrIndex = attrIndex;
        gOmciMulGetData[pri].attribute[attrIndex].doneSeqNum = 0;
        gOmciMulGetData[pri].attribute[attrIndex].maxSeqNum =
            (gOmciMulGetData[pri].attribute[attrIndex].attrSize +
                 OMCI_MSG_BASELINE_GET_NEXT_RSP_LIMIT - 1) /
            OMCI_MSG_BASELINE_GET_NEXT_RSP_LIMIT;

        if(ptr)
        {                        
            OMCI_LOG(OMCI_LOG_LEVEL_WARN, "%s() %d ptr=0x%p, size= %u", __FUNCTION__, __LINE__, ptr, attrSize); 

            LIST_FOREACH(pEntry, &pMe->controllerhead, entries) {
                memset(&ctrlRawEntry, 0, sizeof(omci_controller_tbl_entry_t));
                ControllerEntry_to_network(&pEntry->tableEntry, &ctrlRawEntry);
                memcpy(ptr, &ctrlRawEntry, MIB_TABLE_CONTROLLERTABLE_LEN);
                ptr += MIB_TABLE_CONTROLLERTABLE_LEN;
            }

        }

        OMCI_LOG (
            OMCI_LOG_LEVEL_DBG,
            "Mib_Get: controller table Len %ud\n",
            gOmciMulGetData[pri].attribute[attrIndex].attrSize);
    }
	else if (MIB_IsInAttrSet(&attrSet, MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX)) 
	{
        attrIndex = MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX;
        attrSize = MIB_TABLE_AVLUSPMTPTABLE_LEN * (pMe->curAvlUspMtpEntryCnt);
        
        ptr  = gOmciMulGetData[pri].attribute[attrIndex].pAttrValue; 
        if(ptr && attrSize != gOmciMulGetData[pri].attribute[attrIndex].attrSize)/*attrSize change , first free old buffer */
        {
            OMCI_LOG(OMCI_LOG_LEVEL_WARN, "%s() %d ptr=0x%p, size= %u", __FUNCTION__, __LINE__, ptr, gOmciMulGetData[pri].attribute[attrIndex].attrSize);
            gOmciMulGetData[pri].attribute[attrIndex].pAttrValue = NULL;
			free(ptr);
            ptr = NULL;
        }
        
        if(NULL == ptr && attrSize>0) /*Allocate new buffer */
        {
            gOmciMulGetData[pri].attribute[attrIndex].pAttrValue = (UINT8 *)malloc(attrSize);
            ptr  = gOmciMulGetData[pri].attribute[attrIndex].pAttrValue; 
            OMCI_LOG(OMCI_LOG_LEVEL_WARN, "%s() %d ptr=0x%p, size= %u", __FUNCTION__, __LINE__, ptr, attrSize);   
        }

        if(ptr)
        {
            OMCI_LOG(OMCI_LOG_LEVEL_WARN, "%s() %d ptr=0x%p, size= %u", __FUNCTION__, __LINE__, ptr, attrSize); 
            gOmciMulGetData[pri].attribute[attrIndex].attrSize = attrSize;
            gOmciMulGetData[pri].attribute[attrIndex].attrIndex = attrIndex;
            gOmciMulGetData[pri].attribute[attrIndex].doneSeqNum = 0;
			gOmciMulGetData[pri].attribute[attrIndex].maxSeqNum =
                (gOmciMulGetData[pri].attribute[attrIndex].attrSize +
                     OMCI_MSG_BASELINE_GET_NEXT_RSP_LIMIT - 1) /
                OMCI_MSG_BASELINE_GET_NEXT_RSP_LIMIT;

            LIST_FOREACH(pMtpEntry, &pMe->avlUspMtphead, entries) {
				memcpy(serviceName, pMtpEntry->serviceName, MIB_TABLE_AVLUSPMTPTABLE_LEN);
				GOS_HtonByte(serviceName, MIB_TABLE_AVLUSPMTPTABLE_LEN);
                memcpy(ptr, serviceName, MIB_TABLE_AVLUSPMTPTABLE_LEN);
                ptr += MIB_TABLE_AVLUSPMTPTABLE_LEN;
            }

        }

    }

    return GOS_OK;
}

GOS_ERROR_CODE usp_controller_table_oper(omci_controller_tbl_entry_t *p)
{
 	MIB_TABLE_NETWORK_ADDR_T networkAddr, *pMibNetworkAddr = NULL;
    MIB_TABLE_LARGE_STRING_T largeString, *pMibLargeString = NULL;
	MIB_TABLE_LARGE_STRING_T largeString_code, *pMibLargeString_code = NULL;
    MIB_TABLE_AUTH_SEC_METHOD_T authSecMethod, *pMibAuthenSecMethod = NULL; 
	#if 0
	MIB_TABLE_NETWORK_ADDR_T networkAddr2, *pMibNetworkAddr2 = NULL;
    MIB_TABLE_LARGE_STRING_T largeString2, *pMibLargeString2 = NULL;
    MIB_TABLE_AUTH_SEC_METHOD_T authSecMethod2, *pMibAuthenSecMethod2 = NULL; 
	
	MIB_TABLE_NETWORK_ADDR_T networkAddr3, *pMibNetworkAddr3 = NULL;
    MIB_TABLE_LARGE_STRING_T largeString3, *pMibLargeString3 = NULL;
    MIB_TABLE_AUTH_SEC_METHOD_T authSecMethod3, *pMibAuthenSecMethod3 = NULL; 
	#endif
	mgmt_cfg_msg_t mgmtInfo;

    memset(&mgmtInfo, 0, sizeof(mgmt_cfg_msg_t));

	UINT32 loop, offset = 0;
	
	if (p->tableCtrl != SET_CTRL_DELETE_ALL)
	{
		mgmtInfo.op_id = OP_RESET_USP_CONTROLLER;
	}
	
	if (p->tableCtrl == SET_CTRL_DELETE)
	{
		mgmtInfo.op_id = OP_DEL_USP_CONTROLLER;
		mgmtInfo.cfg.usp.tbl_entry.controller_info.instnum = p->controller_network_addr;
	}

	if (p->tableCtrl == SET_CTRL_WRITE)
	{
		mgmtInfo.op_id = OP_SET_USP_CONTROLLER;
		
		mgmtInfo.cfg.usp.tbl_entry.controller_info.instnum = p->controller_network_addr;
		
		networkAddr.EntityId = p->controller_network_addr;
		if (TRUE == mib_FindEntry(MIB_TABLE_NETWORK_ADDR_INDEX, &networkAddr, &pMibNetworkAddr))
		{
			largeString.EntityId = pMibNetworkAddr->AddrPtr;
			if (TRUE == mib_FindEntry(MIB_TABLE_LARGE_STRING_INDEX, &largeString, &pMibLargeString))
			{
				if (pMibLargeString)
				{
					for (loop = 0; loop < pMibLargeString->NumOfParts; loop++)
					{
						offset = MIB_TABLE_LARGE_STRING_PART_LEN * loop;

						memcpy(mgmtInfo.cfg.usp.tbl_entry.controller_info.controller_url + offset,
							(UINT8 *)pMibLargeString->Part1 + offset + loop, MIB_TABLE_LARGE_STRING_PART_LEN);
					}
				}
			}
		
			authSecMethod.EntityId = pMibNetworkAddr->SecurityPtr;
			if (TRUE == mib_FindEntry(MIB_TABLE_AUTH_SEC_METHOD_INDEX, &authSecMethod, &pMibAuthenSecMethod))
			{
				if (pMibAuthenSecMethod)
				{
					memcpy(mgmtInfo.cfg.usp.tbl_entry.controller_info.controller_username, 
						(UINT8 *)(pMibAuthenSecMethod->Username1),
						strlen(pMibAuthenSecMethod->Username1) + 1);
					memcpy(mgmtInfo.cfg.usp.tbl_entry.controller_info.controller_password, 
						(UINT8 *)(pMibAuthenSecMethod->Password),
						strlen(pMibAuthenSecMethod->Password) + 1);
				}	
			}

			mgmtInfo.cfg.usp.tbl_entry.controller_info.associatedTag = p->associatedTag;

			largeString_code.EntityId = p->provisioning_code;
			if (TRUE == mib_FindEntry(MIB_TABLE_LARGE_STRING_INDEX, &largeString_code, &pMibLargeString_code))
			{
				if (pMibLargeString_code)
					{
						for (loop = 0; loop < pMibLargeString_code->NumOfParts; loop++)
						{
							offset = MIB_TABLE_LARGE_STRING_PART_LEN * loop;

							memcpy(mgmtInfo.cfg.usp.tbl_entry.controller_info.provisioningCode + offset,
								(UINT8 *)pMibLargeString_code->Part1 + offset + loop, MIB_TABLE_LARGE_STRING_PART_LEN);
						}
					}	
			}

			mgmtInfo.cfg.usp.tbl_entry.controller_info.usp_retry_min_wait_interval = p->usp_retry_min_wait_interval;
			mgmtInfo.cfg.usp.tbl_entry.controller_info.usp_retry_interval_multiplier = p->usp_retry_interval_multiplier;
			memcpy(mgmtInfo.cfg.usp.tbl_entry.controller_info.mtp_used, p->mtp_used, MIB_TABLE_AVLUSPMTPTABLE_LEN);
			
		}
		#if 0 
		networkAddr2.EntityId = p->forward_addr;
		if (TRUE == mib_FindEntry(MIB_TABLE_NETWORK_ADDR_INDEX, &networkAddr2, &pMibNetworkAddr2))
		{
			largeString2.EntityId = pMibNetworkAddr2->AddrPtr;
			if (TRUE == mib_FindEntry(MIB_TABLE_LARGE_STRING_INDEX, &largeString2, &pMibLargeString2))
			{
				if (pMibLargeString2)
				{
					for (loop = 0; loop < pMibLargeString2->NumOfParts; loop++)
					{
						offset = MIB_TABLE_LARGE_STRING_PART_LEN * loop;

						memcpy(mgmtInfo.cfg.usp.tbl_entry.controller_info.fwd_url + offset,
							(UINT8 *)pMibLargeString2->Part1 + offset + loop, MIB_TABLE_LARGE_STRING_PART_LEN);
					}
				}
			}
		
			authSecMethod2.EntityId = pMibNetworkAddr2->SecurityPtr;
			if (TRUE == mib_FindEntry(MIB_TABLE_AUTH_SEC_METHOD_INDEX, &authSecMethod2, &pMibAuthenSecMethod2))
			{
				if (pMibAuthenSecMethod2)
				{
					memcpy(mgmtInfo.cfg.usp.tbl_entry.controller_info.fwd_username, 
						(UINT8 *)(pMibAuthenSecMethod2->Username1),
						strlen(pMibAuthenSecMethod2->Username1) + 1);
					memcpy(mgmtInfo.cfg.usp.tbl_entry.controller_info.fwd_password, 
						(UINT8 *)(pMibAuthenSecMethod2->Password),
						strlen(pMibAuthenSecMethod2->Password) + 1);
				}	
			}			
		}
		mgmtInfo.cfg.usp.tbl_entry.controller_info.retry_after_forward_fail_sec = p->retry_second;

		networkAddr3.EntityId = p->backup_server;
		if (TRUE == mib_FindEntry(MIB_TABLE_NETWORK_ADDR_INDEX, &networkAddr3, &pMibNetworkAddr3))
		{
			largeString3.EntityId = pMibNetworkAddr3->AddrPtr;
			if (TRUE == mib_FindEntry(MIB_TABLE_LARGE_STRING_INDEX, &largeString3, &pMibLargeString3))
			{
				if (pMibLargeString3)
				{
					for (loop = 0; loop < pMibLargeString3->NumOfParts; loop++)
					{
						offset = MIB_TABLE_LARGE_STRING_PART_LEN * loop;

						memcpy(mgmtInfo.cfg.usp.tbl_entry.controller_info.backup_server_url + offset,
							(UINT8 *)pMibLargeString3->Part1 + offset + loop, MIB_TABLE_LARGE_STRING_PART_LEN);
					}
				}
			}
		
			authSecMethod3.EntityId = pMibNetworkAddr3->SecurityPtr;
			if (TRUE == mib_FindEntry(MIB_TABLE_AUTH_SEC_METHOD_INDEX, &authSecMethod3, &pMibAuthenSecMethod3))
			{
				if (pMibAuthenSecMethod3)
				{
					memcpy(mgmtInfo.cfg.usp.tbl_entry.controller_info.backup_server_username, 
						(UINT8 *)(pMibAuthenSecMethod3->Username1),
						strlen(pMibAuthenSecMethod3->Username1) + 1);
					memcpy(mgmtInfo.cfg.usp.tbl_entry.controller_info.backup_server_password, 
						(UINT8 *)(pMibAuthenSecMethod3->Password),
						strlen(pMibAuthenSecMethod3->Password) + 1);
				}	
			}			
		}
		#endif
	}

	if (p->tableCtrl == SET_CTRL_WRITE ||
		p->tableCtrl == SET_CTRL_DELETE ||
		p->tableCtrl == SET_CTRL_DELETE_ALL)
	{
		feature_api(FEATURE_API_L3SVC_MGMT_CFG_SET, &mgmtInfo, sizeof(mgmt_cfg_msg_t));
	}
	 return GOS_OK;
}

GOS_ERROR_CODE FttrMqttAgentDrvCfg(void* pOldRow, void* pNewRow, MIB_OPERA_TYPE operationType, MIB_ATTRS_SET attrSet, UINT32 pri)
{
	MIB_TABLE_FTTRMQTTAGENT_T *pAgent = NULL, *pOldAgent = NULL, *pMibFttrMqttAgent = NULL, oldAgent;
	controllerTableEntry_t *ptr = NULL, *pNew = NULL, entry;
	omci_controller_tbl_entry_t *pRawEntry = NULL;
	GOS_ERROR_CODE ret = GOS_OK;
	BOOL bFound;

	pOldAgent = (MIB_TABLE_FTTRMQTTAGENT_T *) pOldRow;
	pAgent = (MIB_TABLE_FTTRMQTTAGENT_T *) pNewRow;
	oldAgent.EntityId = pAgent->EntityId;

	OMCI_ERR_CHK(OMCI_LOG_LEVEL_WARN, (!mib_FindEntry(MIB_TABLE_FTTRMQTTAGENT_INDEX, &oldAgent, &pMibFttrMqttAgent)), GOS_FAIL);
	switch(operationType)
	{
		case MIB_ADD:
			//TBD
			break;
		case MIB_SET:
			if(MIB_IsInAttrSet(&attrSet, MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX))
			{
				pRawEntry = &entry.tableEntry;
				memcpy(pRawEntry, pAgent->ControllerTbl, sizeof(omci_controller_tbl_entry_t));
				
				// transfer to network order.
				pRawEntry->controller_network_addr			= GOS_Htons(pRawEntry->controller_network_addr);
				pRawEntry->associatedTag					= GOS_Htons(pRawEntry->associatedTag);
				pRawEntry->provisioning_code				= GOS_Htons(pRawEntry->provisioning_code);
				pRawEntry->usp_retry_min_wait_interval		= GOS_Htons(pRawEntry->usp_retry_min_wait_interval);
				pRawEntry->usp_retry_interval_multiplier	= GOS_Htons(pRawEntry->usp_retry_interval_multiplier);
				//GOS_HtonByte(pRawEntry->mtp_used, MIB_TABLE_AVLUSPMTPTABLE_LEN);
				
				#if 0
				pRawEntry->forward_addr						= GOS_Htons(pRawEntry->forward_addr);
				pRawEntry->retry_second						= GOS_Htons(pRawEntry->retry_second);
				// Baseline OMCI message format with Message contents size = 32 bytes
				// The below field cannot be 
				pRawEntry->backup_server					= GOS_Htons(pRawEntry->backup_server);
				#endif

				switch(pRawEntry->tableCtrl)
				{
					case SET_CTRL_WRITE:
						bFound = FALSE;
						LIST_FOREACH(ptr, &pMibFttrMqttAgent->controllerhead, entries)
						{
							if(pRawEntry->controller_network_addr == ptr->tableEntry.controller_network_addr)
							{
								//replace
								ptr->tableEntry.controller_network_addr			= pRawEntry->controller_network_addr;
								ptr->tableEntry.associatedTag					= pRawEntry->associatedTag;
								ptr->tableEntry.provisioning_code 				= pRawEntry->provisioning_code;
								ptr->tableEntry.usp_retry_min_wait_interval 	= pRawEntry->usp_retry_min_wait_interval;
								ptr->tableEntry.usp_retry_interval_multiplier 	= pRawEntry->usp_retry_interval_multiplier;
								memcpy(ptr->tableEntry.mtp_used, pRawEntry->mtp_used, MIB_TABLE_AVLUSPMTPTABLE_LEN);
								//ptr->tableEntry.forward_addr					= pRawEntry->forward_addr;
								//ptr->tableEntry.retry_second					= pRawEntry->retry_second;
								//ptr->tableEntry.backup_server					= pRawEntry->backup_server;
								bFound = TRUE;
								break;
							}
						}
						// TBD: trigger tr142
						ret = usp_controller_table_oper(pRawEntry);
						if (!bFound)
						{
							/*not found, create new entry*/
							pNew = (controllerTableEntry_t *)malloc(sizeof(controllerTableEntry_t));
							OMCI_ERR_CHK(OMCI_LOG_LEVEL_WARN, (!pNew), GOS_FAIL);
							memcpy(pNew, &entry, sizeof(controllerTableEntry_t));
							
							//pNew->tableEntry.tableCtrl=0;
							OMCI_LOG(OMCI_LOG_LEVEL_DBG,"add controller entry");
							
							LIST_INSERT_HEAD(&pMibFttrMqttAgent->controllerhead, pNew, entries);
							pMibFttrMqttAgent->curControllerEntryCnt++;
						}
						break;
					case SET_CTRL_DELETE:
						LIST_FOREACH(ptr, &pMibFttrMqttAgent->controllerhead, entries)
						{
							if(pRawEntry->controller_network_addr == ptr->tableEntry.controller_network_addr)
							{
								// TBD: trigger tr142
								ret = usp_controller_table_oper(pRawEntry);
								/*delete specific entry with the same key */
								OMCI_LOG(OMCI_LOG_LEVEL_DBG,"delete controller entry");
								LIST_REMOVE(ptr, entries);
								free(ptr);
								pMibFttrMqttAgent->curControllerEntryCnt--;
								break;
							}
						}
						break;
					case SET_CTRL_DELETE_ALL:
						ptr = LIST_FIRST(&pMibFttrMqttAgent->controllerhead);
						while (NULL != ptr)
						{
							// TBD: trigger TR142
							ret = usp_controller_table_oper(&(ptr->tableEntry));
							LIST_REMOVE(ptr, entries);
							free(ptr);
							ptr = LIST_FIRST(&pMibFttrMqttAgent->controllerhead);
						}
						LIST_INIT(&pMibFttrMqttAgent->controllerhead);
						pMibFttrMqttAgent->curControllerEntryCnt = 0;

						break;
					default:
						break;
				}
			}
			
			break;
			case MIB_GET:
				OMCI_LOG(OMCI_LOG_LEVEL_DBG, "FTTR MQTT Agent --> GET table attribute");
				FttrMqttAgentAttrTypeTableMibGet(pOldAgent, attrSet, pri);
			break;
		default:
			break;
	}

	OMCI_LOG(OMCI_LOG_LEVEL_DBG,"%s: process end, tr142_ret=%u\n", __FUNCTION__, ret);

	return GOS_OK;
}

GOS_ERROR_CODE mibTable_init(MIB_TABLE_INDEX tableId)
{
	UINT8 proprietary_mib_cb_bitmask = 0;
    UINT8 isIgnore = 0;
    if(GOS_OK == omci_ignore_mib_table_check(OMCI_ME_CLASS_FTTR_MQTT_AGENT, OMCI_ME_CLASS_SUB_DEFAULT, &isIgnore))
    {
        if(isIgnore)
        {
            OMCI_PRINT("Ignore classId:%d", OMCI_ME_CLASS_FTTR_MQTT_AGENT);
            return GOS_FAIL;
        }

    }
    gMibFttrMqttAgentTableInfo.Name = "FttrMqttAgent";
    gMibFttrMqttAgentTableInfo.ShortName = "FMA";
    gMibFttrMqttAgentTableInfo.Desc = "FTTR MQTT Agent";
    gMibFttrMqttAgentTableInfo.ClassId = (UINT32)(OMCI_ME_CLASS_FTTR_MQTT_AGENT);
    gMibFttrMqttAgentTableInfo.InitType = (UINT32)(OMCI_ME_INIT_TYPE_ONU);
    gMibFttrMqttAgentTableInfo.StdType = (UINT32)(OMCI_ME_TYPE_PROPRIETARY);
    gMibFttrMqttAgentTableInfo.ActionType = (UINT32)(OMCI_ME_ACTION_SET | OMCI_ME_ACTION_GET | OMCI_ME_ACTION_GET_NEXT | OMCI_ME_ACTION_SET_TABLE);
    gMibFttrMqttAgentTableInfo.pAttributes = &(gMibFttrMqttAgentAttrInfo[0]);

    gMibFttrMqttAgentTableInfo.attrNum = MIB_TABLE_FTTRMQTTAGENT_ATTR_NUM;
    gMibFttrMqttAgentTableInfo.entrySize = sizeof(MIB_TABLE_FTTRMQTTAGENT_T);
    gMibFttrMqttAgentTableInfo.pDefaultRow = &gMibFttrMqttAgentDefRow;

    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].Name = "EntityId";
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX - MIB_TABLE_FIRST_INDEX].Name = "AvlUspMtp";
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX - MIB_TABLE_FIRST_INDEX].Name = "ControllerTbl";

    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].Desc = "Entity ID";
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX - MIB_TABLE_FIRST_INDEX].Desc = "Available USP MTP";
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX - MIB_TABLE_FIRST_INDEX].Desc = "Controller Table";

    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].DataType = MIB_ATTR_TYPE_UINT16;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX - MIB_TABLE_FIRST_INDEX].DataType = MIB_ATTR_TYPE_TABLE;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX - MIB_TABLE_FIRST_INDEX].DataType = MIB_ATTR_TYPE_TABLE;

    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].Len = 2;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX - MIB_TABLE_FIRST_INDEX].Len = MIB_TABLE_AVLUSPMTPTABLE_LEN;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX - MIB_TABLE_FIRST_INDEX].Len = MIB_TABLE_CONTROLLERTABLE_LEN;

    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].IsIndex = TRUE;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX - MIB_TABLE_FIRST_INDEX].IsIndex = FALSE;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX - MIB_TABLE_FIRST_INDEX].IsIndex = FALSE;

    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].MibSave = TRUE;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX - MIB_TABLE_FIRST_INDEX].MibSave = TRUE;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX - MIB_TABLE_FIRST_INDEX].MibSave = TRUE;

    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].OutStyle = MIB_ATTR_OUT_HEX;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX - MIB_TABLE_FIRST_INDEX].OutStyle = MIB_ATTR_OUT_HEX;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX - MIB_TABLE_FIRST_INDEX].OutStyle = MIB_ATTR_OUT_HEX;

    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].OltAcc = OMCI_ME_ATTR_ACCESS_READ;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX - MIB_TABLE_FIRST_INDEX].OltAcc = OMCI_ME_ATTR_ACCESS_READ;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX - MIB_TABLE_FIRST_INDEX].OltAcc = OMCI_ME_ATTR_ACCESS_READ | OMCI_ME_ATTR_ACCESS_WRITE;
    
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].AvcFlag = FALSE;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX - MIB_TABLE_FIRST_INDEX].AvcFlag = FALSE;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX - MIB_TABLE_FIRST_INDEX].AvcFlag = FALSE;
    
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_ENTITYID_INDEX - MIB_TABLE_FIRST_INDEX].OptionType = OMCI_ME_ATTR_TYPE_MANDATORY;
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_AVLUSPMTP_INDEX - MIB_TABLE_FIRST_INDEX].OptionType = (OMCI_ME_ATTR_TYPE_MANDATORY | OMCI_ME_ATTR_TYPE_TABLE);
    gMibFttrMqttAgentAttrInfo[MIB_TABLE_FTTRMQTTAGENT_CONTROLLERTBL_INDEX - MIB_TABLE_FIRST_INDEX].OptionType = (OMCI_ME_ATTR_TYPE_MANDATORY | OMCI_ME_ATTR_TYPE_TABLE);
    
    memset(&(gMibFttrMqttAgentDefRow.EntityId), 0x00, sizeof(gMibFttrMqttAgentDefRow.EntityId));
    
    memset(gMibFttrMqttAgentDefRow.AvlUspMtp, 0, MIB_TABLE_AVLUSPMTPTABLE_LEN);
    memset(gMibFttrMqttAgentDefRow.ControllerTbl, 0, MIB_TABLE_CONTROLLERTABLE_LEN);
    
    /*add for table type attribute*/
    gMibFttrMqttAgentDefRow.curAvlUspMtpEntryCnt = 0;
    gMibFttrMqttAgentDefRow.curControllerEntryCnt = 0;
    
    LIST_INIT(&gMibFttrMqttAgentDefRow.avlUspMtphead);
    LIST_INIT(&gMibFttrMqttAgentDefRow.controllerhead);

    memset(&gMibFttrMqttAgentOper, 0x0, sizeof(MIB_TABLE_OPER_T));
    gMibFttrMqttAgentOper.meOperDrvCfg = FttrMqttAgentDrvCfg;
    gMibFttrMqttAgentOper.meOperConnCheck = NULL;
    gMibFttrMqttAgentOper.meOperDump = FttrMqttAgentDumpMib;
    gMibFttrMqttAgentOper.meOperConnCfg = NULL;
	gMibFttrMqttAgentOper.meOperCb[PROPRIETARY_MIB_CB_RESET] = omci_mib_fttr_mqtt_agent_reset;
	
    MIB_TABLE_FTTRMQTTAGENT_INDEX = tableId;

    MIB_InfoRegister(tableId, &gMibFttrMqttAgentTableInfo, &gMibFttrMqttAgentOper);
    proprietary_mib_cb_bitmask = (1 << PROPRIETARY_MIB_CB_RESET);
    MIB_Proprietary_Reg(tableId, proprietary_mib_cb_bitmask);

    return GOS_OK;
}